home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / compress / tar321__.zip / SOURCES.ZIP / RESTORE.C < prev    next >
C/C++ Source or Header  |  1997-03-14  |  17KB  |  597 lines

  1. /* restore.c - extract regular files from (tape) archive.
  2.  * This is a part of the Tar program (see file tar.c)
  3.  * Author: T.V.Shaporev
  4.  * Creation date: 11 Mar 1993
  5.  */
  6. #include <stdio.h>
  7. #include <errno.h>
  8.  
  9. #include "sysup.h"
  10. #include "modern.h"
  11. #ifdef MODERN
  12. #    include <string.h>
  13. #else
  14.     char *strncpy();
  15.     int  strlen();
  16. #endif
  17.  
  18. #ifdef MSDOS
  19. #    include <dos.h>
  20. #    include <stdlib.h>
  21. #else
  22.     int  access(), creat(), open(), close(), link(), unlink();
  23.     int  write(), chown(), utime();
  24.     char *malloc();
  25.         long lseek();
  26.     void free();
  27. #endif
  28.  
  29. #include "lzwbits.h"
  30. #include "lzwhead.h"
  31. #include "compress.h"
  32. #include "zippipe.h"
  33. #include "crc32.h"
  34. #include "define.h"
  35. #include "lzpack.h"
  36.  
  37. /* Reneaming will expand name for 5 characters at most */
  38. char ofname[MAXTNAME+8+1];
  39.  
  40. void extwrerr()
  41. {
  42.    (void)fprintf(myout, "Tar: error extracting \'%s\'\n", ofname);
  43.    done(EWRITE);
  44. }
  45.  
  46. #ifdef MSDOS
  47. static void setime __ARGS__(( int, long ));
  48.  
  49. static void setime(h, mt)
  50. int h; long mt;
  51. {
  52.    struct date d;
  53.    struct time t;
  54.    unsigned short f[2]; /* DOS file timestamp */
  55.    extern int setftime();
  56.  
  57.    if (m_flag) return;
  58.    unixtodos(mt, &d, &t);
  59.    f[0] = (t.ti_hour << 11) | (t.ti_min << 5) | (t.ti_sec >> 1);
  60.    f[1] = ((d.da_year - 1980) << 9) | (d.da_mon << 5) | d.da_day;
  61.    (void)setftime(h, &f);
  62. }
  63.  
  64. #define wcnt_type unsigned short
  65. #define MAXWARN  8
  66.  
  67. static renamed = FALSE;
  68. static wcnt_type wcount = 0;
  69. static nwarn = 0;
  70.  
  71. static struct { wcnt_type lru; char wnm[MAXTNAME]; } wlist[MAXWARN];
  72.  
  73. static void wrename __ARGS__(( char * ));
  74.  
  75. static void wrename(n)
  76. char *n;
  77. {
  78.    register i;
  79.  
  80.    renamed = FALSE;
  81.    for (i=0; i<nwarn; i++) {
  82.      if (strncmp(wlist[i].wnm, n, MAXTNAME) == 0) {
  83.         wlist[i].lru = wcount++; return;
  84.      }
  85.    }
  86.    (void)printf("Tar: warning: renamed to \'%s\'\n", n);
  87.    if (nwarn < MAXWARN) {
  88.       i = nwarn++;
  89.    } else {
  90.       register j;
  91.       /* Find the least recently used entry */
  92.       for (i=0, j=1; j<MAXWARN; j++) {
  93.          if (wlist[j].lru < wlist[i].lru) i = j;
  94.       }
  95.    }
  96.    (void)strncpy(wlist[i].wnm, n, MAXTNAME);
  97.    wlist[i].lru = wcount++;
  98. }
  99.  
  100. #define CH_DOT '-'
  101. #define CH_BAD '$'
  102.  
  103. static void uname __ARGS__(( char * ));
  104.  
  105. static void uname(fname) /* convert UNIX file name to DOS */
  106. char fname[];
  107. {
  108.    static char invalid[] = "^+=/[]:;\',?*\\<>|\".";
  109.    register char *p = fname;
  110.    register i, offext/* offset to file name extension */;
  111.    register j, limcpy, tmpren;
  112.  
  113.    if (p[1] == ':' && (p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z'))
  114.       p += 2;
  115.  
  116.    tmpren = FALSE;
  117.    while (*p) {
  118.       if (*p == '/') {
  119.          ++p; /* Forget dir name changes */ tmpren = FALSE;
  120.       }
  121.  
  122.       for (offext=i=0; p[i] && p[i]!='/'; i++) {
  123.          if (p[i] == '.') {
  124.             if (i == 0) {
  125.                if (p[1]=='.' && (p[2]=='/' || p[2]=='\0')) {
  126.                   /* This is '..' directory, skip */ ++i;
  127.                } else if (p[1]!='/' && p[1]!='\0') {
  128.                   /* This is not current directory */
  129.                   p[0] = CH_DOT; tmpren = TRUE;
  130.                }
  131.             } else {
  132.                if (offext) {
  133.                   p[offext] = CH_DOT; tmpren = TRUE;
  134.                }
  135.                offext = i;
  136.             }
  137.          } else if (p[i]<=' ' || p[i]>'~' || strchr(invalid, p[i])) {
  138.             p[i] = CH_BAD; tmpren = TRUE;
  139.          }
  140.       }
  141.       if (!offext) offext = i;
  142.       limcpy = MAXTNAME - (int)(p-fname) - offext;
  143.       i -= offext;
  144.       if (offext <= 8) {
  145.          j = offext;
  146.       } else {
  147.          (void)strncpy(p+8, p+offext, i>4 ? 4 : limcpy);
  148.          tmpren = TRUE;
  149.          j = 8;
  150.       }
  151.       if (i <= 4) {
  152.          j += i;
  153.       } else {
  154.          (void)strncpy(p+(offext>8 ? 12 : offext+4), p+i+offext, limcpy-i);
  155.          tmpren = TRUE;
  156.          j += 4;
  157.       }
  158.       p += j;
  159.    }
  160.    if (tmpren) renamed = TRUE;
  161. }
  162. #else
  163. #    define setime(h,t)
  164. #    define uname(s)
  165. #endif
  166.  
  167. int makedir __ARGS__((char *, int));
  168. int testdir __ARGS__((char *));
  169.  
  170. /*ARGSUSED*/ int makedir(p, to_print)
  171. char *p; int to_print;
  172. {
  173. #ifdef UNIX
  174. #   ifdef RMKDIR
  175.          if (mkdir(p, 0777) != 0 && to_print) {
  176.             (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p);
  177.             return ERROR;
  178.          }
  179. #   else
  180.          switch (bincall("mkdir", p)) {
  181.             case  0: break;
  182.             case -1: (void)fprintf(myout, "Tar: fault run mkdir!\n");
  183.             default: done(0);
  184.          }
  185. #   endif
  186.          if (!o_flag) (void)chown(p,(int)st.st_uid,(int)st.st_gid);
  187. #endif
  188. #ifdef MSDOS
  189.          if (mkdir(p) != 0 && to_print) {
  190.             (void)fprintf(myout, "Tar: can\'t create directory \'%s\'\n", p);
  191.             return ERROR;
  192.          }
  193. #endif
  194.    return 0;
  195. }
  196.  
  197. int testdir(p)
  198. char *p;
  199. {
  200.    register j;
  201.    register k = FALSE;
  202. #ifndef UNIX
  203.    register char *q = p;
  204. #endif
  205. #ifdef MSDOS
  206.    renamed = FALSE;
  207. #endif
  208.    for (j=1; j<MAXTNAME && p[j]; j++) {/* check directories */
  209.       if (p[j] == '/') {
  210.          p[j] = 0;
  211. #ifndef UNIX
  212.          uname(q); q = p + j + 1;
  213. #endif
  214.          if (access(p, 1) < 0) {
  215.             if (makedir(p, TRUE) != 0) return ERROR;
  216.             k = TRUE;
  217.          }
  218.          p[j] = '/';
  219.       }
  220.    }
  221. #ifdef MSDOS
  222.    if (renamed && v_flag) wrename(p);
  223. #endif
  224.    return k;
  225. }
  226.  
  227. long thisread;
  228.  
  229. int arcget __ARGS__((void))
  230. {
  231.    if (v_flag && !(thisread & 07777)) percent(thisread, st.st_size);
  232.    return thisread<st.st_size ? (++thisread, readbyte()) : EOF;
  233. }
  234.  
  235. static int  o_file, indput;
  236. static long thiscsum;
  237.  
  238. static void dstput(c)
  239. int c;
  240. {
  241.    thiscsum += c; ((unsigned char *)pk_out)[indput++] = c;
  242.    if (indput >= pksize) {
  243.       if (write(o_file, pk_out, pksize) != pksize) {
  244.          if (v_flag) (void)fprintf(myout, "\n");
  245.          extwrerr();
  246.       }
  247.       indput = 0;
  248.    }
  249. }
  250.  
  251. #define savename(s) ((void)strncpy(ofname,(s),MAXTNAME),ofname[MAXTNAME]='\0')
  252.  
  253. static int newfile __ARGS__(( char *, int ));
  254.  
  255. static int newfile(name, mode)
  256. char *name; int mode;
  257. {
  258. #ifdef MSDOS
  259.    int h, caccess;
  260.    unsigned cmode;
  261.    register k = 0;
  262.  
  263.    savename(name);
  264.    caccess = o_flag ? OA_CREATENEW : OA_TRUNCATE+OA_CREATENEW;
  265.    cmode = mapumode(mode);
  266.    if ((h = lopen4(name, OM_WRONLY, caccess, cmode)) < 0) {
  267.       if (errno == ENOENT || errno == ENOPATH) {
  268.          if ((k=testdir(name)) == TRUE)
  269.             h = lopen4(name, OM_WRONLY, caccess, cmode);
  270.       } else if (errno == EEXIST && o_flag) {
  271.          static char del[4] = "^~\'`";
  272.          register unsigned ntry = 0;
  273.          register nb, len, i, j;
  274.          char suffix[5];
  275.          int maxlen = lfn_active == TRUE ? 255: 8;
  276.  
  277.          if ((len = strlen(name)) > MAXTNAME) goto end;
  278.          for (nb=len; nb>0 && name[nb-1]!='/' && name[nb-1]!=':'; nb--) {
  279.             if (name[nb] == '.') len = nb;
  280.          }
  281.          len -= nb;
  282.          do {
  283.             ++ntry;
  284.             /* Convert number of try into suffix */
  285.             suffix[0] = del[ntry & 3];
  286.             for (i=1, j=ntry>>2; j; j>>=5) {
  287.                suffix[i++] = ((j & 037) < 10 ? '0': 'A'-10) + (j & 037);
  288.             }
  289.             suffix[i] = '\0';
  290.             /* Replace end of the name by suffix */
  291.             if (len < maxlen) {
  292.                (void)strcat(
  293.                   strcpy(ofname+nb+
  294.                          (len+i<maxlen ? len : maxlen-i), suffix),
  295.                   name+nb+len);
  296.             } else {
  297.                (void)strncpy(ofname+nb+len-i, suffix, i);
  298.             }
  299.             renamed = TRUE;
  300.             h = lopen4(ofname, OM_WRONLY, caccess, cmode);
  301.          } while (h<0 && errno == EEXIST && ntry);
  302.       }
  303.    }
  304. end:
  305.    if (h < 0) {
  306.       if (k!=ERROR) (void)fprintf(myout,"Tar: can\'t create \'%s\'\n",name);
  307.    } else {
  308.       if (renamed && v_flag) wrename(ofname);
  309.       /*if ((mode & 0777) == 0) (void)chmod(name, 1, FA_HIDDEN);*/
  310.    }
  311.    return h;
  312. #else
  313.    register j = 0;
  314.    register h;
  315.  
  316.    savename(name);
  317.    do {
  318.       if ((h = creat(name, (int)(mode & 07777))) >= 0) {
  319.          if (!o_flag) (void)chown(name, (int)st.st_uid, (int)st.st_gid);
  320.          return h;
  321.       }
  322.    } while (++j < 2 && testdir(name) == TRUE);
  323.  
  324.    if (j > 1) (void)fprintf(myout, "Tar: can\'t create \'%s\'\n", name);
  325.    return ERROR;
  326. #endif
  327. }
  328.  
  329. static void pfile __ARGS__((char *, long, long));
  330.  
  331. static void pfile(name, bytes, blocks)
  332. char name[]; long bytes, blocks;
  333. {
  334.    if (v_flag) {
  335.       (void)fprintf(myout, "x %s, %ld bytes, %ld tape blocks",
  336.                     name, bytes, blocks);
  337.       (void)fflush(myout);
  338.    }
  339. }
  340.  
  341. static int xany __ARGS__((void))
  342. {
  343.    (void)fprintf(stderr, " Extract anyway? ");
  344.    (void)fflush(stderr);
  345.    return YES_NO();
  346. }
  347.  
  348. int restore(p)
  349. register char *p;
  350. {
  351.    register j;
  352.  
  353.    register long bytes, blocks;
  354.    static char no_mem[] = "\nTar: no memory to unpack.";
  355.    static char e[] = "    \n";
  356.    short nx=0, allx; long l=0, xinfo;
  357.    int multy = FALSE; /* Multyvolume processing flag */
  358.    extern int soctul __ARGS__((char*, long*));
  359. #ifdef MSDOS
  360.    renamed = FALSE;
  361. #endif
  362.    if (hblock->m.filetype == GF_MUL) {
  363.       (void)soctul(hblock->x.offset, &xinfo);
  364.       multy = TRUE;
  365.    } else {
  366.       if ((nx = isextent(&allx, &xinfo)) > 0) multy = TRUE;
  367.    }
  368.    bytes  = codesize > st.st_size ? codesize : st.st_size;
  369.    blocks = (st.st_size + BLKSIZE-1)/BLKSIZE;
  370.    if (pktype == PKfLZW && !multy && st.st_size >= codesize) {
  371.       j = strlen(p);
  372.       if (p[--j] != 'Z' || p[--j] != '.') goto regular;
  373.       p[j] = '\0';
  374.       uname(p);
  375.       if ((o_file = newfile(p, st.st_mode)) < 0) {
  376.          skipfile(); return ERROR;
  377.       }
  378.       pfile(p, bytes, blocks);
  379.       p[j] = '.';
  380.       (void)z_getmem(BITS);
  381.       thisread = 0; indput = 0; thiscsum = 0;
  382.       if ((j = dbegin(arcget)) == 0) {
  383.          do {
  384.             j = dpiece(pk_out, pksize);
  385.             if (j > 0) {
  386.                if (write(o_file, pk_out, j) != j) {
  387.                   if (v_flag) (void)fprintf(myout, "\n");
  388.                   extwrerr();
  389.                }
  390.                if (v_flag) percent(thisread, st.st_size);
  391.             }
  392.          } while (j == pksize);
  393.          (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2);
  394.          goto xend;
  395.       } else if (j > 0) {
  396.          if (v_flag) (void)fprintf(myout, " is not in compressed format\n");
  397.       } else {
  398.          if (!xany()) done(ESMALL);
  399.       }
  400.       bacouple(); z_relmem();
  401.    }
  402. regular:
  403.    uname(p);
  404.    if (nx > 1 || (hblock->m.filetype == GF_MUL && xinfo > 0)) {
  405.       /* Multivolume processing */
  406.       if ((o_file = open(p, OM_WRONLY)) >= 0) {
  407.          savename(p);
  408.          if ((l=lseek(o_file, 0L, 2)) == -1L) {
  409.             (void)fprintf(myout, " Tar: \'%s\' seek error\n", p);
  410.             goto fault;
  411.          }
  412.          if (hblock->m.filetype == GF_MUL && l != xinfo) {
  413.             if (w_flag) {
  414.                (void)fprintf(stderr,
  415.                   " Tar: \'%s\' mismatch size. Append? ", p);
  416.                (void)fflush(stderr);
  417.                if (YES_NO()) goto opened;
  418.             } else {
  419.                (void)fprintf(myout,
  420.                   " Tar: warning: \'%s\' mismatch size\n", p);
  421.             }
  422.             l = lseek(o_file, xinfo, 0);
  423.          }
  424.          goto opened;
  425.       } else if (errno == ENOENT) {
  426.          if (w_flag) {
  427.             (void)fprintf(stderr,
  428.                " Tar: \'%s\' does not exist.", p);
  429.             if (!xany()) goto fault;
  430.          } else {
  431.             (void)fprintf(myout,
  432.                " Tar: warning: \'%s\' does not exist\n", p);
  433.             goto fault;
  434.          }
  435.       } else {
  436.          (void)fprintf(myout, "Tar: can\'t append \'%s\'\n", p);
  437.          goto fault;
  438.       }
  439.    }
  440.    if ((o_file = newfile(p, st.st_mode)) < 0) goto fault;
  441. opened:
  442.    pfile(ofname, bytes, blocks);
  443.  
  444.    if (st.st_size >= codesize || multy) {/* file was not packed */
  445.       if (v_flag) {
  446.          if (nx > 0) {
  447.             (void)fprintf(myout," [extent #%d of %d]", nx, allx);
  448.          } else if (hblock->m.filetype == GF_MUL) {
  449.             (void)fprintf(myout," [");
  450.             if (l != xinfo)
  451.                (void)fprintf(myout,"from %ld - ", xinfo);
  452.             (void)fprintf(myout,"append @%ld]", l);
  453.          }
  454.          (void)fprintf(myout, "\n");
  455.       }
  456.       (void)readarch(o_file, st.st_size);
  457.       if (nx > 1 && nx == allx && lseek(o_file, 0L, 2) != xinfo) {
  458.          /* last extent extracted, so check for total file size */
  459.          (void)fprintf(myout,"Tar: warning: \'%s\' changed size\n",ofname);
  460.       }
  461.    } else {/* file was packed */
  462.       if (!pk_out) pk_out = malloc(pksize);
  463.  
  464.       if (hblock->m.srcsum[1] != 'x') {/* Old decompression */
  465.          if (!pk_out || lzgetmem()) {
  466.             (void)fprintf(myout, "%s\n", no_mem);
  467.             done(ESMALL);
  468.          }
  469.          thisread = 0; indput = 0; thiscsum = 0;
  470.  
  471.          l = lzdecode(arcget, dstput, codesize);
  472.          (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2);
  473.          if (indput > 0 && write(o_file, pk_out, indput) != indput)
  474.             extwrerr();
  475.          if (l != codesize) {
  476.             (void)fprintf(myout, "Tar: \'%s\' decode error\n", ofname);
  477.             if (!i_flag) done(EINTER);
  478.          }
  479.          if (thiscsum != longcsum) {
  480.             (void)fprintf(myout, "Tar: \'%s\' checksum error\n", ofname);
  481.          }
  482.       } else {/* Inflation */
  483.          if (!pk_out || unzalloc()) {
  484.             (void)fprintf(myout, "%s\n", no_mem);
  485.             done(ESMALL);
  486.          }
  487.          thisread = 0; indput = 0; thiscsum = 0;
  488.          if (unzopen(arcget, ZIP_RAW)) {
  489.             (void)fprintf(myout, "Tar: unzip error: %s\n",
  490.                                  ziperrlist[ziperror]);
  491.             done(EINTER);
  492.          }
  493.          do {
  494.             j = unzread(pk_out, pksize);
  495.             if (j > 0) {
  496.                if (write(o_file, pk_out, j) != j) {
  497.                   if (v_flag) (void)fprintf(myout, "\n");
  498.                   extwrerr();
  499.                }
  500.                if (v_flag) percent(thisread, st.st_size);
  501.             }
  502.          } while (j == pksize);
  503.          (void)fprintf(myout, v_flag ? e : e+sizeof(e)-2);
  504.  
  505.          if (j != -1) {
  506.             if ((j = unzclose()) == 0) {
  507.                if (getcrc() != longcsum) j = ziperror = BADCRC;
  508.             }
  509.          }
  510.          if (j) {
  511.             (void)fprintf(myout,"Unzip %s: %s\n",
  512.                (j == -1 ? "error" : "warning"), ziperrlist[ziperror]);
  513.             if (j == -1) done(EINTER);
  514.          }
  515.       }
  516.    }
  517. xend:
  518.    j = nx > 0 && nx < allx;
  519. #ifdef MSDOS
  520.    if (!j) setime(o_file, st.st_mtime);
  521. #endif
  522.    (void)close(o_file);
  523.    return j;
  524. fault:
  525.    if (o_file >= 0) (void)close(o_file);
  526.    skipfile();
  527.    return ERROR;
  528. }
  529.  
  530. void makelink(fname, lname)
  531. char *fname, *lname;
  532. {
  533. #ifdef MSDOS
  534. #  define BUFSIZE 8192
  535.    char *buffer = NULL;
  536.    int bufsize = BUFSIZE;
  537. #endif
  538.    register j;
  539.  
  540. #ifdef UNIX
  541.    (void)unlink(fname);
  542.    if ((j = link(lname, fname)) < 0) {
  543.       if (testdir(fname) == TRUE) j = link(lname, fname);
  544.    }
  545.    if (j < 0)
  546.       (void)fprintf(myout,
  547.          "Tar: can\'t link \'%s\' to \'%s\'\n", fname, lname);
  548.    else
  549. #endif
  550. #ifdef MSDOS
  551.    if (l_flag) {/* copy file */
  552.       int inp, out;
  553.       char *buffer; int bufsize;
  554.       long rsize, mtime;
  555.  
  556.       if ((buffer = malloc(BUFSIZE)) == NULL) {
  557.          if (pk_out) {
  558.             buffer = pk_out;
  559.             bufsize = pksize;
  560.          } else {
  561.             buffer = (char *)hblock;
  562.             bufsize = BLKSIZE;
  563.          }
  564.       }
  565.       if ((inp = open(lname, OM_RDONLY)) < 0) {
  566.          cantopen(lname); goto quit;
  567.       }
  568.       if ((out = newfile(fname, st.st_mode)) < 0) {
  569.          (void)close(inp); goto quit;
  570.       }
  571.       rsize = st.st_size;
  572.       mtime = st.st_mtime;
  573.       do {
  574.          if ((j = read(inp, buffer, bufsize)) > 0) {
  575.             rsize -= j;
  576.             if (write(out, buffer, j) != j) {
  577.                extwrerr(); j = ERROR;
  578.             }
  579.          }
  580.       } while (j == bufsize);
  581.       if (j >= 0) setime(out, mtime);
  582.       (void)close(out);
  583.       (void)close(inp);
  584.       if (j < 0) goto quit;
  585.       if (v_flag) (void)fprintf(myout, "x %s copied from %s\n", fname, lname);
  586.       if (rsize != 0)
  587.          (void)fprintf(myout,
  588.             "Tar: warning \'%s\' real size differs from the recorded\n",fname);
  589.    } else
  590. #endif
  591.    if (v_flag) (void)fprintf(myout, "x %s linked to %s\n", fname, lname);
  592. #ifdef MSDOS
  593. quit:
  594.    if (buffer != NULL && bufsize == BUFSIZE) free(buffer);
  595. #endif
  596. }
  597.